//
//  SleepViewModel.swift
//  MoyoungHome
//
//  Created by 李然 on 2022/9/26.
//

import Foundation
import RxCocoa
import RxSwift
import SwiftDate

import MYModule
import UIKit



public class SleepViewModel: ViewModel ,ViewModelType {
    
    public var cellTpe: [CellType]?
    
    public var inPut: Input?
    
    public var outPut: Output?
    
    private var providerDate: Date?
    
    
    public struct Input {
        
        public var provider: SleepProvider?
        public let revealAll: Bool
        public let viewWillAppear: ControlEvent<Bool>

        public init(revealAll: Bool, viewWillAppear: ControlEvent<Bool>) {
            
            self.revealAll = revealAll
            self.viewWillAppear = viewWillAppear
            
            
        }
    }
    
    public struct Output {
        
        public let providerRelay: BehaviorRelay<SleepProvider?>
        
        
        public let segementedChartsViewModel: SleepSegementedChartsViewModel
        
        public let ratio:BehaviorRelay<SleepModel>
        
        public let qualityScore:BehaviorRelay<Int>
        
        public let analysisViewModel: SleepAnalysisViewModel
        
        public let heartData:BehaviorRelay<HeartRateChartLineConfig?>
        
        public let hrvData:BehaviorRelay<HeartRateChartLineConfig?>
        
        public let sleepTemperatureModel: SleepTemperatureViewModel
        
        public let activityViewModel: SleepActivityStatusViewModel
        
        public let sevenDaysTrendsViewModel: SleepSevenDaysTrendsViewModel
        
        public let earlySleepCompare:BehaviorRelay<SleepDataCompareType>
        public let earlyAwakeCompare:BehaviorRelay<SleepDataCompareType>
        public let lessSleepCompare:BehaviorRelay<SleepDataCompareType>
        
        public let dataSource = BehaviorRelay<[CellType]>(value: [])
        
    }
    
    public override init() {
        super.init()
        
        /// 进入前台通知,延时一秒是因为给SDK setTime 留时间
        NotificationCenter.default.rx.notification(UIApplication.willEnterForegroundNotification).take(until: self.rx.deallocated).delay(.seconds(1), scheduler: MainScheduler()).subscribe(onNext: {[weak self] noti in
            
            let provider = self?.providerObserver(input: self?.inPut)
            self?.outPut?.providerRelay.accept(provider)
            
        }).disposed(by: rx.disposeBag)
        
        NotificationCenter.default.rx.notification(.kUpdateUINotification).take(until: self.rx.deallocated).subscribe(onNext: {[weak self] in
            
            self?.notifactionAction(noti: $0)
            
        }).disposed(by: rx.disposeBag)
    }
    
    func notifactionAction(noti: Notification) {
        
        guard let dict = noti.userInfo as? [String: Any], let type = dict["type"] as? NotifactionType else { return }
        
        switch type {
            
        case .sleep, .heartRate, .HRV, .temperature:
            
            /// 更新数据
            let provider = self.providerObserver(input: self.inPut)
            self.outPut?.providerRelay.accept(provider)
            
        default:
            break
            
        }
        
    }
    
    
   
    public func providerObserver(input: Input?) ->SleepProvider {
        guard let provider = input?.provider else {
            let date = Date()
            
             return SleepProvider(date: date)
         }
         return provider
    }
    
    
    public func transform(input: Input) -> Output {
        
        self.inPut = input
        
        let providerRelay = BehaviorRelay<SleepProvider?>(value: nil)
        
        input.viewWillAppear.map {[weak self] animted ->SleepProvider? in
              
            let provider = self?.providerObserver(input: input)
           
            return provider
    
        }.bind(to: providerRelay).disposed(by: rx.disposeBag)
        


        let segementedChartsViewModel = SleepSegementedChartsViewModel(providerRelay: providerRelay, revealAll: input.revealAll, viewWillAppear: input.viewWillAppear)
        
        let heartData = BehaviorRelay<HeartRateChartLineConfig?>(value: nil)
        
        providerRelay.map { provider ->HeartRateChartLineConfig? in
            
            guard let provider = provider, let config = provider.configModel(provider.curDayDetail, list: provider.heartData) else {
                return nil
            }
            return config
            
        }.bind(to: heartData).disposed(by: rx.disposeBag)
        
        let hrvData = BehaviorRelay<HeartRateChartLineConfig?>(value: nil)
        providerRelay.map { provider -> HeartRateChartLineConfig? in
            
            guard let provider = provider, let config = provider.configModel(provider.curDayDetail, list: provider.hrvData) else {
                return nil
            }
           
            return config

        }.bind(to: hrvData).disposed(by: rx.disposeBag)
        
        /// 体温
        let sleepTemperatureViewModel = SleepTemperatureViewModel(providerRelay: providerRelay)
        
        let ratio = BehaviorRelay<SleepModel>(value: SleepModel())
        providerRelay.map {
            
            $0?.curDayDetail ?? SleepModel()
            
        }.bind(to: ratio).disposed(by: rx.disposeBag)
        
        let qualityScore = BehaviorRelay<Int>(value: 0)
        providerRelay.map {
            
            $0?.calculator.quality ?? 0
            
        }.bind(to: qualityScore).disposed(by: rx.disposeBag)
     
        let analysisViewModel = SleepAnalysisViewModel(providerRelay: providerRelay)
        let sevenDaysTrendsViewModel = SleepSevenDaysTrendsViewModel(providerRelay: providerRelay)
        let activityStatusViewModel =  SleepActivityStatusViewModel(providerRelay: providerRelay)
        
        let earlySleepCompare = BehaviorRelay<SleepDataCompareType>(value: SleepDataCompareType.graterEarlySleep(index: 0, percentage: 0))
        providerRelay.map {
            
            guard let provider = $0 else {
                return SleepDataCompareType.graterEarlySleep(index: 0, percentage: 0)
            }
            let tuple = provider.getEarlySleepCompareResult()
            
            return SleepDataCompareType.graterEarlySleep(index: tuple.index, percentage: tuple.percentage)
            
        }.bind(to: earlySleepCompare).disposed(by: rx.disposeBag)
        
        
        let earlyAwakeCompare = BehaviorRelay<(SleepDataCompareType)>(value: SleepDataCompareType.graterEarlyAwake(index: 0, percentage: 0))
        providerRelay.map {
            
            guard let provider = $0 else {
                return SleepDataCompareType.graterEarlyAwake(index: 0, percentage: 0)
            }
            
           let tuple = provider.getEarlyAwakeCompareResult()
            return SleepDataCompareType.graterEarlyAwake(index: tuple.index, percentage: tuple.percentage)
            
        }.bind(to: earlyAwakeCompare).disposed(by: rx.disposeBag)
    
        let lessSleepCompare = BehaviorRelay<(SleepDataCompareType)>(value: SleepDataCompareType.lessSleep(index: 0, percentage: 0))
        providerRelay.map {
            
            guard let provider = $0 else {
                return SleepDataCompareType.lessSleep(index: 0, percentage: 0)
            }
            
           let tuple = provider.getLesssleepCompareResult()
            return SleepDataCompareType.lessSleep(index: tuple.index, percentage: tuple.percentage)
            
        }.bind(to: lessSleepCompare).disposed(by: rx.disposeBag)
        
        
        /// 刷新 需要指令获取的数据
        let sleepDataUpdateSubject = BehaviorRelay<Bool>(value: false)
        let sleepArchiveDataUpdateSubject = BehaviorRelay<Bool>(value: false)
        let sleepTemperatureDataUpdateSubject = BehaviorRelay<Bool>(value: false)
        let heartRateUpdateSubject = BehaviorRelay<Bool>(value: false)
        let HRVUpdateSubject = BehaviorRelay<Bool>(value: false)
        
       Observable.combineLatest(sleepDataUpdateSubject, sleepArchiveDataUpdateSubject, sleepTemperatureDataUpdateSubject, heartRateUpdateSubject, HRVUpdateSubject).share().map { (update, update1, update2, update3, update4) ->Bool in
           
           return update && update1 && update2 && update3 && update4
            
       }.subscribe(onNext: {[weak self] in
           
           if $0 == false {
               return
           }
           
           let provider = providerRelay.value
           self?.providerDate = provider?.date
           
           providerRelay.accept(provider)
           
       }).disposed(by: rx.disposeBag)
        
 
        providerRelay.filter {[weak self] in
            
           guard let provider = $0 else {
                return false
            }
            
            // 只在今天才去同步指令数据
            if !provider.date.isToday {
                return false
            }
 
            guard let providerDate = self?.providerDate else {
                return true
            }

            return providerDate.day != provider.date.day
            
        }.subscribe(onNext: { provider in
            
            guard let provider = provider else { return }
            
            
            // 15天睡眠历史记录
            BluetoothManager.shared.getSleepDatas(of: provider.date, backward: 15, forcedUpdate: false) {
                
                sleepDataUpdateSubject.accept(true)
                
            }
            
            // 15获取睡眠活动量
            BluetoothManager.shared.getSleepArchiveDatas(of: provider.date, backward: 15, forcedUpdate: false) {
                
                sleepArchiveDataUpdateSubject.accept(true)
                
            }
            
            // 15体温
            BluetoothManager.shared.getSleepTemperatureDatas(of: provider.date, backward: 15, forcedUpdate: false) {
                
                sleepTemperatureDataUpdateSubject.accept(true)
            }
            
            // 15天的心率
            BluetoothManager.shared.getTimingHeartRates(of: provider.date, backward: 15, forcedUpdate: false) {
                
                heartRateUpdateSubject.accept(true)
                
            }
            
            // 15天的HRV
            BluetoothManager.shared.getTimingHRVs(of: provider.date, backward: 15, forcedUpdate: false) {
                
                HRVUpdateSubject.accept(true)
                
            }
            
            
        }).disposed(by: rx.disposeBag)
        
    
        let outPut = Output(providerRelay: providerRelay,
                      segementedChartsViewModel: segementedChartsViewModel,
                      ratio: ratio,
                      qualityScore: qualityScore,
                      analysisViewModel: analysisViewModel,
                      heartData: heartData,
                      hrvData: hrvData,
                      sleepTemperatureModel:  sleepTemperatureViewModel,
                      activityViewModel: activityStatusViewModel,
                      sevenDaysTrendsViewModel: sevenDaysTrendsViewModel,
                      earlySleepCompare: earlySleepCompare,
                      earlyAwakeCompare: earlyAwakeCompare,
                      lessSleepCompare: lessSleepCompare)
        
        
        providerRelay.map {[weak self] _ ->[CellType] in
            
            guard let self = self else {
                return []
            }
            
           return self.cellTypes(revealAll: input.revealAll, outPut: outPut)
            
        }.bind(to: outPut.dataSource).disposed(by: rx.disposeBag)
        
        self.outPut = outPut
        return outPut
    }
    
    fileprivate func cellTypes(revealAll: Bool, outPut: Output) -> [CellType] {
        
        var cellTypes: [CellType] =  [
            
            .segementedCharts(outPut.segementedChartsViewModel),
            .ratio(outPut.ratio),
            .score(outPut.qualityScore),
            .analysis(outPut.analysisViewModel),
            .heartRate(outPut.heartData),
            .avgerageHRV(outPut.hrvData),
            .temperature(outPut.sleepTemperatureModel),
            .activityStatus(outPut.activityViewModel),
            .sevenDaysSleepTrends(outPut.sevenDaysTrendsViewModel),
            .sleepEarly(outPut.earlySleepCompare),
            .getUpEarly(outPut.earlyAwakeCompare),
            .sleepLess(outPut.lessSleepCompare)

        ]
        
        if revealAll == false {
            cellTypes = [
                .segementedCharts(outPut.segementedChartsViewModel),
                .ratio(outPut.ratio),
                .score(outPut.qualityScore),
            ]
        }
        
        return cellTypes
        
    }
    

}

extension SleepViewModel {
    
    public enum CellType {
        
        case segementedCharts(_ viewModel: SleepSegementedChartsViewModel)
        case ratio(_ relay: BehaviorRelay<SleepModel>)
        case score(_ relay: BehaviorRelay<Int>)
        case analysis(_ viewModel: SleepAnalysisViewModel)
        case heartRate(_ relay: BehaviorRelay<HeartRateChartLineConfig?>)
        case avgerageHRV(_ relay: BehaviorRelay<HeartRateChartLineConfig?>)
        case temperature(_ viewModel: SleepTemperatureViewModel)
        case activityStatus(_ viewModel: SleepActivityStatusViewModel)
        case sevenDaysSleepTrends(_ viewModel: SleepSevenDaysTrendsViewModel)
        case sleepEarly(_ relay: BehaviorRelay<SleepDataCompareType>)
        case getUpEarly(_ relay: BehaviorRelay<SleepDataCompareType>)
        case sleepLess(_ relay: BehaviorRelay<SleepDataCompareType>)
        
    }
    
    
}

extension SleepViewModel.CellType {
    
    public var viewModel: Any {
        
        switch self {
            
        case .segementedCharts(let viewModel):
            return viewModel
        case .ratio(let relay):
            return relay
        case .score(let relay):
            return relay
        case .analysis(let viewModel):
            return viewModel
        case .heartRate(let relay):
            return relay
        case .avgerageHRV(let relay):
            return relay
        case .activityStatus(let viewModel):
            return viewModel
        case .sevenDaysSleepTrends(let viewModel):
            return viewModel
        case .sleepEarly(let relay):
            return relay
        case .getUpEarly(let relay):
            return relay
        case .sleepLess(let relay):
            return relay
        case .temperature(let viewModel):
            return viewModel
            
        }
        
    }
    
    public var cellClass: AnyClass {
        return NSClassFromString("DaRings.\(self.indentifier)")!
    }
    
   public var indentifier: String {
        
        switch self {
            
        case .segementedCharts:
            return "SleepSegementedChartsCell"
        case .ratio:
            return "SleepRatioCell"
        case .score:
            return "SleepQualityScoreCell"
        case .analysis:
            return "SleepAnalysisCell"
        case .heartRate:
            return "SleepHearRateCell"
        case .avgerageHRV:
            return "SleepAverageHRVCell"
        case .activityStatus:
            return "SleepActivityStatusCell"
        case .sevenDaysSleepTrends:
            return "SleepRecentSevenDaysCell"
            
        case .sleepEarly:
            return "SleepBeyondCell"
        case .getUpEarly:
            return "SleepBeyondCell"
        case .sleepLess:
            return "SleepBeyondCell"
        case .temperature:
            return "SleepTemperatureCell"
        }
        
    }
}
